/*********************************************************************************************************
 *
 *	模块名称 :ls命令执行模块
 *	文件名称 :Ls_Command.c
 *	版    本 : V1.0
 *	说    明 :本模块在用户输入ls指令后开始执行。
 *
 *              注意事项：
 *                务必将编辑器的缩进参数和TAB设置为4来阅读本文件，以使得代码显示整齐。
 *
 *	修改记录 :
 *		版本号       日期         作者        说明
 *		V1.0     2022-05-09     zrx
 *
 *	Copyright (C), 2022-2030, xxxx
 *
 *********************************************************************************************************/

#include "../include/Ls_Command.h"

/*********************************************************************************************************
 *	函 数 名:Ls_Command
 *	功能说明:执行ls相关命令。
 *	形    参:string pointer array User content
 *  全局变量:无
 *	返 回 值:success 0    false -1
 *********************************************************************************************************/

int Ls_Command(char *abuf[20])
{
    char buf[128] = "\0";  //原路径
    char buf1[128] = "\0"; //访问路径
    getcwd(buf, 128);

    for (size_t i = 1; i < 20 && abuf[i]; i++) //查找输入内容是否为打印其他路径下的文件信息
    {
        if (*abuf[i] == '.' || *abuf[i] == '/' || *abuf[i] == '~') //～由于收集模块没有转换此模块，因此～符号暂时无法实现
        {
            int cd = chdir(abuf[i]);
            if (cd == -1)
            {
                perror("fail pathname");
                return -1;
            }
            break;
        }
    }

    DIR *dp = opendir(getcwd(buf1, 128));
    if (dp == NULL)
    {
        perror("fail opendir");
        return -1;
    }

    int isa = 1; //判断用户输入内容中是否存在-a、-al命令
    for (size_t i = 1; i < 20 && abuf[i]; i++)
    {
        if (!strcmp(abuf[i], "-a") || !strcmp(abuf[i], "-al"))
        {
            isa = 0;
        }
    }

    int l = 0; //判断用户输入内容中是否存在-l、-al命令
    for (size_t i = 1; i < 20 && abuf[i]; i++)
    {
        if (!strcmp(abuf[i], "-l") || !strcmp(abuf[i], "-al"))
        {
            l = 1;
        }
    }

    while (1)
    {
        struct dirent *rd = readdir(dp);
        if (rd == NULL)
        {
            break;
        }

        if (isa && rd->d_name[0] == '.') //判断是否跳过隐藏文件
        {
            continue;
        }

        if (l) //判断是否显示文件详细信息
        {
            struct stat *stbuf = (struct stat *)calloc(1, sizeof(struct stat));
            if (stbuf == NULL)
            {
                printf("not enough space");
                return 0;
            }

            int st = stat(rd->d_name, stbuf);

            if (st == -1)
            {
                perror("fail stat");
                return -1;
            }

            int ft = stbuf->st_mode & S_IFMT;
            switch (ft)
            {
            case S_IFBLK:
                putchar('b');
                break;
            case S_IFCHR:
                putchar('c');
                break;
            case S_IFDIR:
                putchar('d');
                break;
            case S_IFREG:
                putchar('-');
                break;
            case S_IFLNK:
                putchar('l');
                break;
            case S_IFSOCK:
                putchar('s');
                break;
            case S_IFIFO:
                putchar('p');
                break;

            default:
                puts("not file type");
                return -1;
            }

            stbuf->st_mode &S_IRUSR ? putchar('r') : putchar('-');
            stbuf->st_mode &S_IWUSR ? putchar('w') : putchar('-');
            stbuf->st_mode &S_IXUSR ? putchar('x') : putchar('-');

            stbuf->st_mode &S_IRGRP ? putchar('r') : putchar('-');
            stbuf->st_mode &S_IWGRP ? putchar('w') : putchar('-');
            stbuf->st_mode &S_IXGRP ? putchar('x') : putchar('-');

            stbuf->st_mode &S_IROTH ? putchar('r') : putchar('-');
            stbuf->st_mode &S_IWOTH ? putchar('w') : putchar('-');
            stbuf->st_mode &S_IXOTH ? putchar('x') : putchar('-');

            struct passwd *un = getpwuid(stbuf->st_uid);
            struct group *gn = getgrgid(stbuf->st_gid);
            printf(" %s %s ", un->pw_name, gn->gr_name);
            printf("%8ld ", stbuf->st_size);

            struct timespec fct = stbuf->st_mtim;
            struct tm *ffct = localtime(&fct.tv_sec);
            printf("%2d月 %4d %02d:%02d ", ffct->tm_mon + 1, ffct->tm_mday, ffct->tm_hour, ffct->tm_min);
            puts(rd->d_name);

            free(stbuf);
            stbuf = NULL;
        }
        else
        {
            printf("%s ", rd->d_name);
        }
    }
    if (!l)
    {
        puts("");
    }

    chdir(buf);
    closedir(dp);

    return 0;
}